/*jslint sub: true */
/*global http, crypto, querystring, parseInt, Service */

/**
 * Абстрактный класс для работы с социальной сетью vk.com.
 *
 * @class
 * @name Service.Vk
 * @extends Service
 */
Service.Vk = Service.$extend({

    /**
     * Идентификатор приложения, присваивается при создании.
     *
     * @public
     * @field
     * @name Service.Vk#id
     * @see Service.Vk#getId
     * @type {Number}
     */
    id : null,

    /**
     * Секретный ключ приложения.
     *
     * @public
     * @field
     * @name Service.Vk#secret
     * @see Service.Vk#getSecret
     * @type {String}
     */
    secret : null,

    /**
     * Название сервисного метода.
     *
     * @public
     * @field
     * @name Service.Vk#method
     * @see Service.Vk#getMethod
     * @type {String}
     */
    method : null,

    /**
     * Полный адрес сервиса.
     *
     * @public
     * @field
     * @name Service.Vk#url
     * @see Service.Vk#getUrl
     * @type {String}
     */
    url : 'http://api.vk.com/api.php',

    /**
     * Версия протокола.
     *
     * @public
     * @field
     * @name Service.Vk#version
     * @see Service.Vk#getVersion
     * @type {String}
     */
    version : '3.0',

    /**
     * Получить идентификатор приложения, присваивается при создании.
     *
     * @public
     * @function
     * @name Service.Vk#getId
     * @see Service.Vk#id
     * @return {Number}
     */
    getId : function () {
        'use strict';
        return this.id;
    },

    /**
     * Получить секретный ключ приложения.
     *
     * @public
     * @function
     * @name Service.Vk#getSecret
     * @see Service.Vk#secret
     * @return {String}
     */
    getSecret : function () {
        'use strict';
        return this.secret;
    },

    /**
     * Получить название сервисного метода.
     *
     * @public
     * @function
     * @name Service.Vk#getMethod
     * @see Service.Vk#method
     * @return {String}
     */
    getMethod : function () {
        'use strict';
        return this.method;
    },

    /**
     * Получить полный адрес сервиса.
     *
     * @public
     * @function
     * @name Service.Vk#getUrl
     * @see Service.Vk#url
     * @return {String}
     */
    getUrl : function () {
        'use strict';
        return this.url;
    },

    /**
     * Получить версию протокола.
     *
     * @public
     * @function
     * @name Service.Vk#getVersion
     * @see Service.Vk#version
     * @return {String}
     */
    getVersion : function () {
        'use strict';
        return this.version;
    },

    /**
     * Конструктор.
     *
     * @public
     * @function
     * @name Service.Vk#$init
     * @param {Object} options
     * @param {Number|String} options.id
     * @param {String} options.secret
     * @param {String} options.method
     * @param {String} [options.url="http://api.vk.com/api.php"]
     * @return {void}
     */
    $init : function (options) {
        'use strict';
        options = options || {};
        var versionType = typeof options['version'];
        // Идентификатор приложения.
        if (/^\d+$/.test(String(options['id'] || ''))) {
            this.id = parseInt(String(options['id']), 10);
        } else {
            // Показываем ошибку, что неверно задан идентификатор приложения.
            throw new TypeError('The application ID is not valid, integer expected.');
        }
        // Секретный ключ приложения.
        if (/^[a-z0-9]+$/i.test(String(options['secret'] || ''))) {
            this.secret = String(options['secret']);
        } else {
            // Показываем ошибку, что неверно задан секретный ключ приложения.
            throw new TypeError('The application secret key does not match the regular expression /^[a-z0-9]$/i.');
        }
        // Название метода.
        if (/^[a-z0-9]+$/i.test(String(options['method'] || ''))) {
            this.method = String(options['method']);
        } else {
            // Показываем ошибку, что неверно задано название метода.
            throw new TypeError('The method name does not match the regular expression /^[a-z0-9]$/i.');
        }
        // Версия протокола.
        if (/^\d+(\.\d+)?$/.test(String(options['version'] || ''))) {
            this.version = String(options['version'] || '');
        } else if (versionType !== 'undefined') {
            // Показываем ошибку, что версия протокола задана не верно.
            throw new TypeError('The protocol version is not valid, expected number.');
        }



        if (typeof options['url'] === 'string') {
            this.url = String(options['url']);
        }
    },

    /**
     * @public
     * @function
     * @name Service.Vk#call
     * @return {void}
     */
    call : function (options, callback) {
        'use strict';
        var signature = [],
            md5sum    = crypto.createHash('md5'),
            request   = [];
        // Параметры запроса к сервису.
        options = options || {};
        options['timestamp'] = parseInt(String(Number(new Date()) / 1000), 10);
        options['api_id']    = this.getId();
        options['method']    = this.getMethod();
        options['random']    = parseInt(String(10000 * Math.random()), 10);
        options['format']    = 'json';
        options['v']         = this.getVersion();
        // Составляем подпись для запроса.
        Object.keys(options).
            sort(function (a, b) {
                if (a > b) { return 1; }
                if (a < b) { return -1; }
                return 0;
            }).forEach(function (key) {
                var variable = {};
                variable[key] = String(options[key] || '');
                request.push(querystring.stringify(variable));
                signature.push(key + '=' + String(options[key] || ''));
            });
        signature.push(this.getSecret());
        md5sum.update(signature.join(''));
        request.push('sig=' + md5sum.digest('hex'));
        // Делаем запрос к сервису.
        http.get(this.getUrl() + '?' + request.join('&'), function (response) {
            response.on("data", function (data) {
                console.log("BODY: " + data);
            });
        }).on('error', function (error) {
            console.log('error:', error);
        });
    }

});
